home *** CD-ROM | disk | FTP | other *** search
- //-----------------------------------------------------------------------------
- // File: cdiacpage.cpp
- //
- // Desc: CDIDeviceActionConfigPage implements the page object used by the UI.
- // A page covers the entire UI minus the device tabs and the bottons at
- // the bottom. The information window, player combo-box, genre combo-
- // box, action list tree, and device view window are all managed by
- // the page.
- //
- // Copyright (C) 1999-2001 Microsoft Corporation. All Rights Reserved.
- //-----------------------------------------------------------------------------
-
- #include "common.hpp"
- #include <initguid.h>
-
- DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
-
-
- // {D0B5C9AE-966F-4510-B955-4D2482C5EB1B}
- DEFINE_GUID(GUID_ActionItem,
- 0xd0b5c9ae, 0x966f, 0x4510, 0xb9, 0x55, 0x4d, 0x24, 0x82, 0xc5, 0xeb, 0x1b);
-
-
- #define DISEM_TYPE_MASK ( 0x00000600 )
- #define DISEM_REL_MASK ( 0x00000100 )
- #define DISEM_REL_SHIFT ( 8 )
- #define DISEM_TYPE_AXIS 0x00000200
- #define DISEM_TYPE_BUTTON 0x00000400
- #define DISEM_TYPE_POV 0x00000600
-
- #define DEVICE_POLLING_INTERVAL 10
- #define DEVICE_POLLING_AXIS_MIN 0
- #define DEVICE_POLLING_AXIS_MAX 100
- #define DEVICE_POLLING_AXIS_MINDELTA 3
- #define DEVICE_POLLING_AXIS_SIGNIFICANT 40
- #define DEVICE_POLLING_AXIS_ACCUMULATION 20
- #define DEVICE_POLLING_ACBUF_START_INDEX 3
- #define DEVICE_POLLING_WHEEL_SCALE_FACTOR 3
-
- // For WINMM.DLL
- HINSTANCE g_hWinMmDLL = NULL;
- FUNCTYPE_timeSetEvent g_fptimeSetEvent = NULL;
-
- //QueryInterface
- STDMETHODIMP CDIDeviceActionConfigPage::QueryInterface(REFIID iid, LPVOID* ppv)
- {
- //null the out param
- *ppv = NULL;
-
- if ((iid == IID_IUnknown) || (iid == IID_IDIDeviceActionConfigPage))
- {
- *ppv = this;
- AddRef();
- return S_OK;
- }
-
- return E_NOINTERFACE;
- }
-
-
- //AddRef
- STDMETHODIMP_(ULONG) CDIDeviceActionConfigPage::AddRef()
- {
- return InterlockedIncrement(&m_cRef);
- }
-
-
- //Release
- STDMETHODIMP_(ULONG) CDIDeviceActionConfigPage::Release()
- {
-
- if (InterlockedDecrement(&m_cRef) == 0)
- {
- delete this;
- return 0;
- }
-
- return m_cRef;
- }
-
-
- //constructor
- CDIDeviceActionConfigPage::CDIDeviceActionConfigPage() :
- m_pDeviceUI(NULL), m_puig(NULL), m_pUIFrame(NULL),
- m_cRef(1), m_lpDiac(NULL), m_State(CFGSTATE_NORMAL),
- m_pCurControl(NULL),
- m_tszIBText(NULL), m_pbmIB(NULL), m_pbmIB2(NULL),
- m_pbmRelAxesGlyph(NULL), m_pbmAbsAxesGlyph(NULL), m_pbmButtonGlyph(NULL),
- m_pbmHatGlyph(NULL), m_pbmCheckGlyph(NULL), m_pbmCheckGlyphDark(NULL),
- m_pRelAxesParent(NULL), m_pAbsAxesParent(NULL), m_pButtonParent(NULL),
- m_pHatParent(NULL), m_pUnknownParent(NULL),
- m_bFirstDeviceData(TRUE), m_cbDeviceDataSize(0), m_nOnDeviceData(0),
- m_dwLastControlType(0),
- m_nPageIndex(-1)
- {
- tracescope(__ts, _T("CDIDeviceActionConfigPage::CDIDeviceActionConfigPage()\n"));
- m_pDeviceData[0] = NULL;
- m_pDeviceData[1] = NULL;
- }
-
-
- //destructor
- CDIDeviceActionConfigPage::~CDIDeviceActionConfigPage()
- {
- tracescope(__ts, _T("CDIDeviceActionConfigPage::~CDIDeviceActionConfigPage()\n"));
-
- // Unattach the parent from the tooltip window so it won't get destroyed.
- SetParent(CFlexWnd::s_ToolTip.m_hWnd, NULL);
-
- if (m_hWnd != NULL)
- Destroy();
-
- FreeResources();
-
- delete m_pDeviceUI;
-
- for (int c = 0; c < 2; c++)
- if (m_pDeviceData[c] != NULL)
- free(m_pDeviceData[c]);
-
- if (m_lpDID != NULL)
- {
- m_lpDID->Unacquire();
- m_lpDID->Release();
- }
- m_lpDID = NULL;
- }
-
-
- STDMETHODIMP CDIDeviceActionConfigPage::Create(DICFGPAGECREATESTRUCT *pcs)
- {
- tracescope(__ts, _T("CDIDeviceActionConfigPage::Create()\n"));
- if (pcs == NULL)
- return E_INVALIDARG;
- DICFGPAGECREATESTRUCT &cs = *pcs;
-
- // validate/save uig and uif
- m_puig = pcs->pUIGlobals;
- m_pUIFrame = pcs->pUIFrame;
- if (m_puig == NULL || m_pUIFrame == NULL)
- return E_INVALIDARG;
-
- // save page index
- m_nPageIndex = pcs->nPage;
- assert(m_nPageIndex >= 0);
-
- // create deviceui with uig, or fail
- m_pDeviceUI = new CDeviceUI(*m_puig, *m_pUIFrame);
- if (m_pDeviceUI == NULL)
- return E_FAIL;
-
- // save the device instance
- m_didi = cs.didi;
- m_lpDID = cs.lpDID;
- if (m_lpDID != NULL)
- m_lpDID->AddRef();
-
- // create the window
- HWND hWnd = NULL;
- assert(m_puig != NULL);
- RECT rect = {0, 0, 1, 1};
- hWnd = CFlexWnd::Create(cs.hParentWnd, rect, FALSE);
-
- // return the handle
- cs.hPageWnd = hWnd;
-
- assert(m_puig != NULL);
-
- // Create the information box
- m_InfoBox.Create(m_hWnd, g_InfoWndRect, TRUE);
- m_InfoBox.SetFont((HFONT)m_puig->GetFont(UIE_USERNAMES));
- m_InfoBox.SetColors(m_puig->GetTextColor(UIE_USERNAMES),
- m_puig->GetBkColor(UIE_USERNAMES),
- m_puig->GetTextColor(UIE_USERNAMESEL),
- m_puig->GetBkColor(UIE_USERNAMESEL),
- m_puig->GetBrushColor(UIE_USERNAMES),
- m_puig->GetPenColor(UIE_USERNAMES));
- SetAppropriateDefaultText();
-
- // Create the check box only if this is a keyboard device.
- if (LOBYTE(LOWORD(m_didi.dwDevType)) == DI8DEVTYPE_KEYBOARD)
- {
- m_CheckBox.Create(m_hWnd, g_CheckBoxRect, FALSE);
- m_CheckBox.SetNotify(m_hWnd);
- m_CheckBox.SetFont((HFONT)m_puig->GetFont(UIE_USERNAMES));
- m_CheckBox.SetColors(m_puig->GetTextColor(UIE_USERNAMES),
- m_puig->GetBkColor(UIE_USERNAMES),
- m_puig->GetTextColor(UIE_USERNAMESEL),
- m_puig->GetBkColor(UIE_USERNAMESEL),
- m_puig->GetBrushColor(UIE_USERNAMES),
- m_puig->GetPenColor(UIE_USERNAMES));
-
- TCHAR tszResourceString[MAX_PATH];
- LoadString(g_hModule, IDS_SORTASSIGNED, tszResourceString, MAX_PATH);
- m_CheckBox.SetText(tszResourceString);
- m_CheckBox.SetCheck(TRUE);
- ::ShowWindow(m_CheckBox.m_hWnd, SW_SHOW);
- }
-
- // create the username dropdown if necessary
- FLEXCOMBOBOXCREATESTRUCT cbcs;
- cbcs.dwSize = sizeof(FLEXCOMBOBOXCREATESTRUCT);
- cbcs.dwFlags = FCBF_DEFAULT;
- cbcs.dwListBoxFlags = FCBF_DEFAULT|FLBF_INTEGRALHEIGHT;
- cbcs.hWndParent = m_hWnd;
- cbcs.hWndNotify = m_hWnd;
- cbcs.bVisible = TRUE;
- cbcs.rect = g_UserNamesRect;
- cbcs.hFont = (HFONT)m_puig->GetFont(UIE_USERNAMES);
- cbcs.rgbText = m_puig->GetTextColor(UIE_USERNAMES);
- cbcs.rgbBk = m_puig->GetBkColor(UIE_USERNAMES);
- cbcs.rgbSelText = m_puig->GetTextColor(UIE_USERNAMESEL);
- cbcs.rgbSelBk = m_puig->GetBkColor(UIE_USERNAMESEL);
- cbcs.rgbFill = m_puig->GetBrushColor(UIE_USERNAMES);
- cbcs.rgbLine = m_puig->GetPenColor(UIE_USERNAMES);
- cbcs.nSBWidth = 11;
-
- if (m_puig->GetNumUserNames() > 0 && m_hWnd != NULL
- )
- {
- for (int i = 0, n = m_puig->GetNumUserNames(); i < n; i++)
- m_UserNames.AddString(SAFESTR(m_puig->GetUserName(i)));
- m_UserNames.AddString(SAFESTR(_T("(unassigned)")));
-
- m_UserNames.Create(&cbcs);
-
- int nUser = m_pUIFrame->GetCurUser(m_nPageIndex);
- if (nUser == -1)
- nUser = m_puig->GetNumUserNames();
- m_UserNames.SetSel(nUser);
- } else
- if (m_hWnd != NULL)
- m_UserNames.SetSel(0); // If only 1 user, still must set selection to 0 or we get error later.
-
- // If we are in view mode, set username combobox to read only so user can't change its value.
- if (!m_puig->InEditMode())
- m_UserNames.SetReadOnly(TRUE);
-
- if (m_puig->GetNumMasterAcFors() > 1 && m_hWnd != NULL)
- {
- for (int i = 0, n = m_puig->GetNumMasterAcFors(); i < n; i++)
- m_Genres.AddString(SAFESTR(m_puig->RefMasterAcFor(i).tszActionMap));
-
- cbcs.rect = g_GenresRect;
- m_Genres.Create(&cbcs);
- m_Genres.SetSel(m_pUIFrame->GetCurGenre());
- }
-
- // return success/fail
- return hWnd != NULL ? S_OK : E_FAIL;
- }
-
- STDMETHODIMP CDIDeviceActionConfigPage::Show(LPDIACTIONFORMATW lpDiActFor)
- {
- // save the format pointer
- m_lpDiac = lpDiActFor;
-
- // force tree init
- InitTree(TRUE);
-
- // show the assignments for the controls
- SetControlAssignments();
-
- // show the assignment for the current control
- ShowCurrentControlAssignment();
-
- // Sort the list if check box is checked.
- if (m_CheckBox.GetCheck())
- m_pDeviceUI->GetCurView()->SortAssigned(TRUE);
-
- // show the window
- if (m_hWnd != NULL)
- ShowWindow(m_hWnd, SW_SHOW);
-
- SetFocus(m_hWnd);
- CFlexWnd::s_CurrPageHwnd = m_hWnd;
-
- return S_OK;
- }
-
- STDMETHODIMP CDIDeviceActionConfigPage::Hide()
- {
- // clear the tree
- ClearTree();
-
- // null the format pointer
- m_lpDiac = NULL;
-
- // hide the window
- if (m_hWnd != NULL)
- ShowWindow(m_hWnd, SW_HIDE);
-
- // If we are in the assign state, exit it.
- if (m_State == CFGSTATE_ASSIGN)
- ExitAssignState();
-
- return S_OK;
- }
-
- void CDIDeviceActionConfigPage::InitIB()
- {
- RECT z = {0,0,0,0};
- SIZE bsize = {0,0};
- m_rectIB = z;
- if (m_pbmIB != NULL)
- {
- if (m_pbmIB->GetSize(&bsize))
- {
- m_rectIB.right = bsize.cx * 2;
- m_rectIB.bottom = bsize.cy;
- }
- }
-
- const int IBORIGINX = 200, IBORIGINY = 394,
- IBTEXTMARGINLEFT = 5;
- POINT ptIBOrigin = {IBORIGINX, IBORIGINY};
-
- m_tszIBText = _T("Click here to see different views of your controller.");
- SIZE tsize = GetTextSize(m_tszIBText, (HFONT)m_puig->GetFont(UIE_VIEWSEL));
- m_ptIBOffset.x = 0;
- m_ptIBOffset.y = 0;
- int tofs = 0;
- if (m_rectIB.bottom < tsize.cy)
- {
- m_rectIB.bottom = tsize.cy;
- m_ptIBOffset.y = (tsize.cy - bsize.cy) / 2;
- }
- else if (tsize.cy < m_rectIB.bottom)
- tofs = (bsize.cy - tsize.cy) / 2;
- m_rectIB.right += tsize.cx;
- if (m_pbmIB != NULL)
- m_rectIB.right += IBTEXTMARGINLEFT * 2;
-
- OffsetRect(&m_rectIB, ptIBOrigin.x, ptIBOrigin.y);
- m_ptIBOffset.x += ptIBOrigin.x;
- m_ptIBOffset.y += ptIBOrigin.y;
-
- m_ptIBOffset2.x = m_rectIB.right - bsize.cx;
- m_ptIBOffset2.y = m_ptIBOffset.y;
-
- m_rectIBText = m_rectIB;
- if (m_pbmIB != NULL)
- m_rectIBText.left += IBTEXTMARGINLEFT + bsize.cx;
- if (m_pbmIB2 != NULL)
- m_rectIBText.right -= IBTEXTMARGINLEFT + bsize.cx;
- m_rectIBText.top += tofs;
-
- // Inialize the two RECTs representing the two arrow bitmaps
- m_rectIBLeft = m_rectIBRight = m_rectIB;
- m_rectIBLeft.right = m_rectIBText.left;
- m_rectIBRight.left = m_rectIBText.right;
- }
-
- void CDIDeviceActionConfigPage::OnInit()
- {
- tracescope(__ts, _T("CDIDeviceActionConfigPage::OnInit()\n"));
- // init resources
- InitResources();
-
- // init IB
- InitIB();
-
- // initialize the device UI
- m_pDeviceUI->Init(m_didi, m_lpDID, m_hWnd, this);
-
- // initialize the device
- InitDevice();
-
- // Start a one-shot timer for click to pick
- if (g_fptimeSetEvent)
- g_fptimeSetEvent(DEVICE_POLLING_INTERVAL, DEVICE_POLLING_INTERVAL,
- CDIDeviceActionConfigPage::DeviceTimerProc, (DWORD_PTR)m_hWnd, TIME_ONESHOT);
-
- // create the tree
- CAPTIONLOOK cl;
- cl.dwMask = CLMF_TEXTCOLOR | CLMF_FONT | CLMF_LINECOLOR;
- cl.rgbTextColor = m_puig->GetTextColor(UIE_CALLOUT);
- cl.rgbLineColor = m_puig->GetPenColor(UIE_BORDER);
- cl.hFont = (HFONT)m_puig->GetFont(UIE_ACTION);
- m_Tree.SetDefCaptionLook(cl);
- cl.rgbTextColor = m_puig->GetTextColor(UIE_CALLOUTHIGH);
- m_Tree.SetDefCaptionLook(cl, TRUE);
- m_Tree.SetBkColor(RGB(0,0,0));
- if (m_puig->InEditMode())
- {
- m_Tree.Create(m_hWnd, g_TreeRect, TRUE, TRUE);
- m_Tree.SetScrollBarColors(
- m_puig->GetBrushColor(UIE_SBTRACK),
- m_puig->GetBrushColor(UIE_SBTHUMB),
- m_puig->GetPenColor(UIE_SBBUTTON));
- }
- }
-
- void CDIDeviceActionConfigPage::InitResources()
- {
- // create glyphs
- if (!m_pbmRelAxesGlyph)
- m_pbmRelAxesGlyph = CBitmap::CreateFromResource(g_hModule, IDB_AXESGLYPH);
- if (!m_pbmAbsAxesGlyph)
- m_pbmAbsAxesGlyph = CBitmap::CreateFromResource(g_hModule, IDB_AXESGLYPH);
- if (!m_pbmButtonGlyph)
- m_pbmButtonGlyph = CBitmap::CreateFromResource(g_hModule, IDB_BUTTONGLYPH);
- if (!m_pbmHatGlyph)
- m_pbmHatGlyph = CBitmap::CreateFromResource(g_hModule, IDB_HATGLYPH);
- if (!m_pbmCheckGlyph)
- m_pbmCheckGlyph = CBitmap::CreateFromResource(g_hModule, IDB_CHECKGLYPH);
- if (!m_pbmCheckGlyphDark)
- m_pbmCheckGlyphDark = CBitmap::CreateFromResource(g_hModule, IDB_CHECKGLYPHDARK);
-
- // create IB bitmaps
- if (!m_pbmIB)
- m_pbmIB = CBitmap::CreateFromResource(g_hModule, IDB_IB);
- if (!m_pbmIB2)
- m_pbmIB2 = CBitmap::CreateFromResource(g_hModule, IDB_IB2);
- }
-
- void CDIDeviceActionConfigPage::FreeResources()
- {
- if (m_pbmRelAxesGlyph)
- delete m_pbmRelAxesGlyph;
- if (m_pbmAbsAxesGlyph)
- delete m_pbmAbsAxesGlyph;
- if (m_pbmButtonGlyph)
- delete m_pbmButtonGlyph;
- if (m_pbmHatGlyph)
- delete m_pbmHatGlyph;
- if (m_pbmCheckGlyph)
- delete m_pbmCheckGlyph;
- if (m_pbmCheckGlyphDark)
- delete m_pbmCheckGlyphDark;
- if (m_pbmIB)
- delete m_pbmIB;
- if (m_pbmIB2)
- delete m_pbmIB2;
- m_pbmRelAxesGlyph = NULL;
- m_pbmAbsAxesGlyph = NULL;
- m_pbmButtonGlyph = NULL;
- m_pbmHatGlyph = NULL;
- m_pbmCheckGlyph = NULL;
- m_pbmCheckGlyphDark = NULL;
- m_pbmIB = NULL;
- m_pbmIB2 = NULL;
- }
-
- void CDIDeviceActionConfigPage::ClearTree()
- {
- m_Tree.FreeAll();
- m_pRelAxesParent = NULL;
- m_pAbsAxesParent = NULL;
- m_pButtonParent = NULL;
- m_pHatParent = NULL;
- m_pUnknownParent = NULL;
- m_dwLastControlType = 0;
- }
-
- void CDIDeviceActionConfigPage::InitTree(BOOL bForceInit)
- {
- // get type of control
- DWORD dwControlType = 0;
- if (m_pCurControl && m_pCurControl->IsOffsetAssigned())
- {
- DWORD dwObjId = m_pCurControl->GetOffset();
-
- if (dwObjId & DIDFT_RELAXIS)
- dwControlType = DIDFT_RELAXIS;
- else if (dwObjId & DIDFT_ABSAXIS)
- dwControlType = DIDFT_ABSAXIS;
- else if (dwObjId & DIDFT_BUTTON)
- dwControlType = DIDFT_BUTTON;
- else if (dwObjId & DIDFT_POV)
- dwControlType = DIDFT_POV;
- }
-
- // Turn off the tree's readonly flag if we are in the assign state.
- // We will turn it on later if current control's action has DIA_APPFIXED.
- if (m_State == CFGSTATE_NORMAL)
- m_Tree.SetReadOnly(TRUE);
- else
- m_Tree.SetReadOnly(FALSE);
-
- // if this control type is the same as the last, do nothing,
- // unless we're force init
- if (m_dwLastControlType == dwControlType && !bForceInit && m_State)
- return;
-
- // delete the whole tree
- ClearTree();
-
- // can't use tree if there is no diac or action array
- if (m_lpDiac == NULL || m_lpDiac->rgoAction == NULL)
- return;
-
- // also can't use if we don't have a control type
- if (dwControlType == 0)
- return;
-
- // prepare margin rects
- RECT labelmargin = {14, 6, 3, 3};
- RECT itemmargin = {14, 1, 3, 2};
-
- // set default indents
- m_Tree.SetRootChildIndent(5);
- m_Tree.SetDefChildIndent(12);
-
- // add the control type sections
- m_Tree.SetDefMargin(labelmargin);
- TCHAR tszResourceString[MAX_PATH];
- switch (dwControlType)
- {
- case DIDFT_RELAXIS:
- LoadString(g_hModule, IDS_AXISACTIONS, tszResourceString, MAX_PATH);
- m_pRelAxesParent = m_Tree.DefAddItem(tszResourceString);
- break;
-
- case DIDFT_ABSAXIS:
- LoadString(g_hModule, IDS_AXISACTIONS, tszResourceString, MAX_PATH);
- m_pAbsAxesParent = m_Tree.DefAddItem(tszResourceString);
- break;
-
- case DIDFT_BUTTON:
- LoadString(g_hModule, IDS_BUTTONACTIONS, tszResourceString, MAX_PATH);
- m_pButtonParent = m_Tree.DefAddItem(tszResourceString);
- break;
-
- case DIDFT_POV:
- LoadString(g_hModule, IDS_POVACTIONS, tszResourceString, MAX_PATH);
- m_pHatParent = m_Tree.DefAddItem(tszResourceString);
- break;
-
- default:
- return;
- }
-
- // populate the tree
- m_Tree.SetDefMargin(itemmargin);
- for (unsigned int i = 0; i < m_lpDiac->dwNumActions; i++)
- {
- DIACTIONW *pAction = m_lpDiac->rgoAction + i;
- CFTItem *pItem = NULL;
-
- if (pAction == NULL)
- continue;
-
- switch (pAction->dwSemantic & DISEM_TYPE_MASK)
- {
- case DISEM_TYPE_AXIS:
- // Must distinguish between relative and absolute
- switch((pAction->dwSemantic & DISEM_REL_MASK) >> DISEM_REL_SHIFT)
- {
- case 0: pItem = m_pAbsAxesParent; break;
- case 1: pItem = m_pRelAxesParent; break;
- }
- break;
- case DISEM_TYPE_BUTTON: pItem = m_pButtonParent; break;
- case DISEM_TYPE_POV: pItem = m_pHatParent; break;
- }
-
- if (pItem == NULL)
- continue;
-
- // Add action with this name
- CFTItem *pAlready = GetItemWithActionNameAndSemType(pAction->lptszActionName, pAction->dwSemantic);
- if (!pAlready)
- {
- LPTSTR acname = AllocLPTSTR(pAction->lptszActionName);
- pItem = m_Tree.DefAddItem(acname, pItem, ATTACH_LASTCHILD); // This might return NULL.
- free(acname);
- if (pItem)
- pItem->SetUserData((LPVOID)(new RGLPDIACW));
- }
- else
- {
- pItem = pAlready;
- }
-
- if (pItem == NULL)
- continue;
-
- pItem->SetUserGUID(GUID_ActionItem);
- RGLPDIACW *pacs = (RGLPDIACW *)pItem->GetUserData();
- if (pacs)
- pacs->SetAtGrow(pacs->GetSize(), pAction);
-
- if (pAlready)
- {
- // The tree already has an action with this name. Check the DIA_APPFIXED flag for each DIACTION
- // that this item holds.
- DWORD dwNumActions = GetNumItemLpacs(pItem);
- for (DWORD i = 0; i < dwNumActions; ++i)
- {
- LPDIACTIONW lpExistingAc = GetItemLpac(pItem, i);
- // If the DIACTION that is assigned to this device has DIA_APPFIXED flag, then
- // the other must have it too.
- if (lpExistingAc && IsEqualGUID(lpExistingAc->guidInstance, m_didi.guidInstance))
- {
- if (lpExistingAc->dwFlags & DIA_APPFIXED)
- {
- // If this DIACTION has DIA_APPFIXED, then all DIACTIONs must have it too.
- for (DWORD j = 0; j < dwNumActions; ++j)
- {
- LPDIACTIONW lpChangeAc = GetItemLpac(pItem, j);
- if (lpChangeAc)
- lpChangeAc->dwFlags |= DIA_APPFIXED;
- }
- }
-
- break; // Break the loop since we already found the DIACTION that is assigned.
- }
- }
- } // if (pAlready)
- }
-
- // show all
- m_Tree.GetRoot()->ExpandAll();
- m_dwLastControlType = dwControlType;
- }
-
- int CompareActionNames(LPCWSTR acname1, LPCWSTR acname2)
- {
- #ifdef CFGUI__COMPAREACTIONNAMES_CASE_INSENSITIVE
- return _wcsicmp(acname1, acname2);
- #else
- return wcscmp(acname1, acname2);
- #endif
- }
-
- CFTItem *CDIDeviceActionConfigPage::GetItemWithActionNameAndSemType(LPCWSTR acname, DWORD dwSemantic)
- {
- CFTItem *pItem = m_Tree.GetFirstItem();
- for (; pItem != NULL; pItem = pItem->GetNext())
- {
- if (!pItem->IsUserGUID(GUID_ActionItem))
- continue;
-
- LPDIACTIONW lpac = GetItemLpac(pItem);
- if (!lpac)
- continue;
-
- // Check semantic type
- if ((lpac->dwSemantic & DISEM_TYPE_MASK) != (dwSemantic & DISEM_TYPE_MASK))
- continue;
-
- // If both are axis, check for relative/absolute
- if ((lpac->dwSemantic & DISEM_TYPE_MASK) == DISEM_TYPE_AXIS)
- if ((lpac->dwSemantic & DISEM_REL_MASK) != (dwSemantic & DISEM_REL_MASK))
- continue;
-
- // Check name
- if (CompareActionNames(lpac->lptszActionName, acname) == 0)
- return pItem;
- }
-
- return NULL;
- }
-
- void CDIDeviceActionConfigPage::OnPaint(HDC hDC)
- {
- TCHAR tszResourceString[MAX_PATH];
- CPaintHelper ph(*m_puig, hDC);
-
- ph.SetBrush(UIB_BLACK);
- RECT rect;
- GetClientRect(&rect);
- ph.Rectangle(rect, UIR_SOLID);
-
- ph.SetText(UIC_BORDER, UIC_BLACK);
- {
- rect = g_UserNamesTitleRect;
- LoadString(g_hModule, IDS_PLAYER_TITLE, tszResourceString, MAX_PATH);
- DrawText(hDC, tszResourceString, -1, &rect, DT_CENTER|DT_NOCLIP|DT_NOPREFIX);
- }
- if (m_puig->GetNumMasterAcFors() > 1)
- {
- rect = g_GenresTitleRect;
- LoadString(g_hModule, IDS_GENRE_TITLE, tszResourceString, MAX_PATH);
- DrawText(hDC, tszResourceString, -1, &rect, DT_CENTER|DT_NOCLIP|DT_NOPREFIX);
- }
-
- // Draw tree window title and outline if we are in edit mode.
- if (m_puig->InEditMode())
- {
- COLORREF BorderColor = m_puig->GetColor(UIC_BORDER);
- if (m_Tree.GetReadOnly())
- BorderColor = RGB(GetRValue(BorderColor)>>1, GetGValue(BorderColor)>>1, GetBValue(BorderColor)>>1);
-
- ::SetTextColor(hDC, BorderColor); // Use the muted color if tree is read only.
- // Draw tree window title (Available Actions)
- rect = g_TreeTitleRect;
- LoadString(g_hModule, IDS_AVAILABLEACTIONS_TITLE, tszResourceString, MAX_PATH);
- DrawText(hDC, tszResourceString, -1, &rect, DT_CENTER|DT_NOCLIP|DT_NOPREFIX);
- // Draw tree window outline
- HGDIOBJ hPen, hOldPen;
- if (m_Tree.GetReadOnly())
- {
- hPen = CreatePen(PS_SOLID, 0, BorderColor);
- hOldPen = ::SelectObject(hDC, hPen);
- }
- else
- ph.SetPen(UIP_BORDER);
-
- RECT rc = g_TreeRect;
- InflateRect(&rc, 1, 1);
- Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
- if (m_Tree.GetReadOnly())
- {
- ::SelectObject(hDC, hOldPen);
- DeleteObject(hPen);
- }
- }
-
- if (m_pDeviceUI->GetNumViews() < 2)
- return;
-
- if (m_pbmIB != NULL)
- m_pbmIB->Draw(hDC, m_ptIBOffset);
- if (m_pbmIB2 != NULL)
- m_pbmIB2->Draw(hDC, m_ptIBOffset2);
- if (m_tszIBText != NULL)
- {
- ph.SetElement(UIE_VIEWSEL);
- RECT rect = m_rectIBText;
- DrawText(hDC, m_tszIBText, -1, &rect, DT_NOCLIP | DT_NOPREFIX);
- }
- }
-
- void CDIDeviceActionConfigPage::SetCurrentControl(CDeviceControl *pControl)
- {
- // If the new control is the same as the old, no need to do anything.
- if (m_pCurControl == pControl)
- return;
- if (m_pCurControl != NULL)
- {
- m_pCurControl->Unhighlight();
- // If we don't have a current control, then invalidate the view so that the old callout can be repainted.
- // If there is a current control, the view will be invalidated by Highlight().
- if (!pControl)
- m_pCurControl->Invalidate();
- }
- m_pCurControl = pControl;
- if (m_pCurControl != NULL)
- m_pCurControl->Highlight();
- ShowCurrentControlAssignment();
- }
-
- CFTItem *CDIDeviceActionConfigPage::GetItemForActionAssignedToControl(CDeviceControl *pControl)
- {
- if (!pControl)
- return NULL;
-
- // find the item for the action assigned to this control, if any
- CFTItem *pItem = m_Tree.GetFirstItem();
- for (; pItem != NULL; pItem = pItem->GetNext())
- {
- if (!pItem->IsUserGUID(GUID_ActionItem))
- continue;
-
- for (int i = 0, n = GetNumItemLpacs(pItem); i < n; i++)
- {
- LPDIACTIONW lpac = GetItemLpac(pItem, i);
- if (!lpac)
- continue;
-
- if (IsEqualGUID(lpac->guidInstance, m_didi.guidInstance) &&
- GetOffset(lpac) == pControl->GetOffset())
- return pItem;
- }
- }
-
- return NULL;
- }
-
- int CDIDeviceActionConfigPage::GetNumItemLpacs(CFTItem *pItem)
- {
- if (pItem == NULL)
- return 0;
-
- RGLPDIACW *pacs = (RGLPDIACW *)pItem->GetUserData();
- if (!pacs)
- return 0;
- else
- return pacs->GetSize();
- }
-
- LPDIACTIONW CDIDeviceActionConfigPage::GetItemLpac(CFTItem *pItem, int i)
- {
- if (pItem == NULL)
- return NULL;
-
- RGLPDIACW *pacs = (RGLPDIACW *)pItem->GetUserData();
- if (!pacs || i < 0 || i >= pacs->GetSize())
- return NULL;
- else
- return pacs->GetAt(i);
- }
-
- void CDIDeviceActionConfigPage::ShowCurrentControlAssignment()
- {
- // init the tree
- InitTree();
-
- // if we don't have a control...
- if (m_pCurControl == NULL)
- {
- // select nothing
- m_Tree.SetCurSel(NULL);
- return;
- }
-
- // find the item for the action assigned to this control, if any
- CFTItem *pItem = GetItemForActionAssignedToControl(m_pCurControl);
-
- // if we didn't find a match...
- if (!pItem)
- {
- // select nothing
- m_Tree.SetCurSel(NULL);
- return;
- }
-
- // We need to check if the action this control is assigned to has DIA_APPFIXED flag.
- // If it does, this control cannot be remapped to another action.
- // We prevent this by setting the tree control to read-only, so it can't receive any clicks.
- LPDIACTIONW lpAc = GetItemLpac(pItem); // Get the action
- if (lpAc && (lpAc->dwFlags & DIA_APPFIXED))
- m_Tree.SetReadOnly(TRUE);
-
- // otherwise, show item and select it
- pItem->EnsureVisible();
- m_Tree.SetCurSel(pItem);
- }
-
- void CDIDeviceActionConfigPage::DeviceUINotify(const DEVICEUINOTIFY &uin)
- {
- switch (uin.msg)
- {
- case DEVUINM_NUMVIEWSCHANGED:
- Invalidate();
- break;
-
- case DEVUINM_SELVIEW:
- // set the view
- m_pDeviceUI->SetView(uin.selview.nView);
-
- // show the assignments for the controls
- SetControlAssignments();
-
- // select nothing
- SetCurrentControl(NULL);
- break;
-
- case DEVUINM_ONCONTROLDESTROY:
- if (uin.control.pControl == m_pCurControl)
- m_pCurControl = NULL;
- break;
-
- case DEVUINM_CLICK:
- ExitAssignState();
- switch (uin.from)
- {
- case DEVUINFROM_CONTROL:
- SetCurrentControl(uin.control.pControl);
- SetAppropriateDefaultText();
- break;
- case DEVUINFROM_VIEWWND:
- break;
- }
- break;
-
- case DEVUINM_DOUBLECLICK:
- switch (uin.from)
- {
- case DEVUINFROM_CONTROL:
- EnterAssignState();
- break;
- }
- break;
-
- case DEVUINM_MOUSEOVER:
- SetAppropriateDefaultText();
- break;
-
- case DEVUINM_RENEWDEVICE:
- HWND hParent = GetParent(m_hWnd);
- CConfigWnd *pCfgWnd = (CConfigWnd *)GetFlexWnd(hParent);
- if (pCfgWnd)
- {
- LPDIRECTINPUTDEVICE8W lpDID = pCfgWnd->RenewDevice(m_didi.guidInstance);
- if (lpDID)
- {
- // Destroy the device instance we have
- if (m_lpDID) m_lpDID->Release();
- lpDID->AddRef();
- m_lpDID = lpDID;
- }
- m_pDeviceUI->SetDevice(lpDID); // Sets the device pointer in CDeviceUI (no need to AddRef)
- }
- }
- }
-
- void CDIDeviceActionConfigPage::UnassignCallout()
- {
- // find the item for the action assigned to this control, if any
- CFTItem *pItem = GetItemForActionAssignedToControl(m_pCurControl);
- if (pItem)
- {
- LPDIACTIONW lpac = GetItemLpac(pItem);
- // Only unassign if the action doesn't have DIA_APPFIXED flag.
- if (lpac && !(lpac->dwFlags & DIA_APPFIXED))
- {
- ActionClick(NULL);
- m_Tree.Invalidate();
- }
- }
- // Sort the list if the check box is checked.
- if (m_CheckBox.GetCheck())
- m_pDeviceUI->GetCurView()->SortAssigned(TRUE);
- }
-
- void CDIDeviceActionConfigPage::NullAction(LPDIACTIONW lpac)
- {
- if (lpac == NULL)
- return;
-
- SetInvalid(lpac);
-
- }
-
- void CDIDeviceActionConfigPage::UnassignActionsAssignedTo(const GUID &guidInstance, DWORD dwOffset)
- {
- if (m_lpDiac == NULL || m_lpDiac->rgoAction == NULL)
- return;
-
- if (IsEqualGUID(guidInstance, GUID_NULL))
- return;
-
- // assign any actions assigned to this control to nothing
- DWORD i;
- LPDIACTIONW lpac;
- for (i = 0, lpac = m_lpDiac->rgoAction; i < m_lpDiac->dwNumActions; i++, lpac++)
- if (IsEqualGUID(guidInstance, lpac->guidInstance) && dwOffset == GetOffset(lpac)/*->dwInternalOffset*/)
- {
- GlobalUnassignControlAt(guidInstance, dwOffset);
- NullAction(lpac);
- }
- }
-
- void CDIDeviceActionConfigPage::UnassignControl(CDeviceControl *pControl)
- {
- if (pControl == NULL)
- return;
-
- // make sure the control itself indicates unassignment
- pControl->SetCaption(g_tszUnassignedControlCaption);
- }
-
- void CallUnassignControl(CDeviceControl *pControl, LPVOID pVoid, BOOL bFixed)
- {
- CDIDeviceActionConfigPage *pThis = (CDIDeviceActionConfigPage *)pVoid;
- pThis->UnassignControl(pControl);
- }
-
- void CDIDeviceActionConfigPage::GlobalUnassignControlAt(const GUID &guidInstance, DWORD dwOffset)
- {
- if (IsEqualGUID(guidInstance, GUID_NULL))
- return;
-
- if (IsEqualGUID(guidInstance, m_didi.guidInstance))
- m_pDeviceUI->DoForAllControlsAtOffset(dwOffset, CallUnassignControl, this);
- }
-
- // this function must find whatever control is assigned to this action and unassign it
- void CDIDeviceActionConfigPage::UnassignAction(LPDIACTIONW slpac)
- {
- // call UnassignSpecificAction for each action with the same name
- // as this one, including this one
-
- if (slpac == NULL)
- return;
-
- CFTItem *pItem = GetItemWithActionNameAndSemType(slpac->lptszActionName, slpac->dwSemantic);
- if (!pItem)
- return;
-
- RGLPDIACW *pacs = (RGLPDIACW *)pItem->GetUserData();
- if (!pacs)
- return;
-
- for (int i = 0; i < pacs->GetSize(); i++)
- UnassignSpecificAction(pacs->GetAt(i));
- }
-
- void CDIDeviceActionConfigPage::UnassignSpecificAction(LPDIACTIONW lpac)
- {
- if (lpac == NULL)
- return;
-
- if (IsEqualGUID(lpac->guidInstance, GUID_NULL))
- return;
-
- // if there's a control with this instance/offset, unassign it
- UnassignActionsAssignedTo(lpac->guidInstance, GetOffset(lpac)/*->dwInternalOffset*/);
- GlobalUnassignControlAt(lpac->guidInstance, GetOffset(lpac)/*->dwInternalOffset*/);
-
- // now actually null the action
- NullAction(lpac);
- }
-
- void CDIDeviceActionConfigPage::AssignCurrentControlToAction(LPDIACTIONW lpac)
- {
- // if there is a control, unassign it
- if (m_pCurControl != NULL)
- {
- UnassignControl(m_pCurControl);
- GUID guidInstance;
- DWORD dwOffset;
- m_pCurControl->GetInfo(guidInstance, dwOffset);
- UnassignActionsAssignedTo(guidInstance, dwOffset);
- }
-
- // if there is an action, unassign it
- if (lpac != NULL)
- UnassignAction(lpac);
-
- // can only continue if we have both
- if (lpac == NULL || m_pCurControl == NULL)
- return;
-
- // here we should have a control and an action
- assert(lpac != NULL);
- assert(m_pCurControl != NULL);
-
- // because an action can only be assigned to one control,
- // make sure this action is unassigned first
- UnassignAction(lpac);
-
- // now actually assign
- DWORD ofs;
- m_pCurControl->GetInfo(lpac->guidInstance, ofs/*lpac->dwInternalOffset*/);
- SetOffset(lpac, ofs);
- LPTSTR acname = AllocLPTSTR(lpac->lptszActionName);
- m_pCurControl->SetCaption(acname, lpac->dwFlags & DIA_APPFIXED);
- free(acname);
-
- // Sort the action list if check box is checked
- if (m_CheckBox.GetCheck())
- {
- m_pDeviceUI->GetCurView()->SortAssigned(TRUE);
- // Scroll so that we scroll to make this visible since it might be displaced by sorting.
- m_pDeviceUI->GetCurView()->ScrollToMakeControlVisible(m_pCurControl->GetCalloutMaxRect());
- }
- }
-
- void CDIDeviceActionConfigPage::ActionClick(LPDIACTIONW lpac)
- {
- if (m_pCurControl != NULL)
- {
- AssignCurrentControlToAction(lpac);
-
- // Set assignment since other views may have the same callout and
- // they need to be updated too.
- SetControlAssignments();
- }
- // Change the state back to normal
- ExitAssignState();
- }
-
- void CDIDeviceActionConfigPage::SetControlAssignments()
- {
- assert(!IsEqualGUID(m_didi.guidInstance, GUID_NULL));
-
- m_pDeviceUI->SetAllControlCaptionsTo(g_tszUnassignedControlCaption);
-
- if (m_lpDiac == NULL || m_lpDiac->rgoAction == NULL)
- return;
-
- DWORD i;
- LPDIACTIONW lpac;
- for (i = 0, lpac = m_lpDiac->rgoAction; i < m_lpDiac->dwNumActions; i++)
- {
- lpac = m_lpDiac->rgoAction + i;
-
- if (IsEqualGUID(lpac->guidInstance, GUID_NULL))
- continue;
-
- if (!IsEqualGUID(lpac->guidInstance, m_didi.guidInstance))
- continue;
-
- LPTSTR acname = AllocLPTSTR(lpac->lptszActionName);
- m_pDeviceUI->SetCaptionForControlsAtOffset(GetOffset(lpac)/*->dwInternalOffset*/, acname, lpac->dwFlags & DIA_APPFIXED);
- free(acname);
- }
- }
-
- void CDIDeviceActionConfigPage::DoViewSel()
- {
- m_ViewSelWnd.Go(m_hWnd, m_rectIB.left, m_rectIB.top, m_pDeviceUI);
- }
-
- void CDIDeviceActionConfigPage::OnClick(POINT point, WPARAM, BOOL bLeft)
- {
- if (!bLeft)
- return;
-
- // Unhighlight current callout
- ExitAssignState();
-
- if (m_pDeviceUI->GetNumViews() > 1)
- {
- int iCurView = m_pDeviceUI->GetCurViewIndex();
-
- if (PtInRect(&m_rectIBLeft, point))
- m_pDeviceUI->SetView(iCurView == 0 ? m_pDeviceUI->GetNumViews() - 1 : iCurView - 1);
- if (PtInRect(&m_rectIBRight, point))
- m_pDeviceUI->SetView(iCurView == m_pDeviceUI->GetNumViews() - 1 ? 0 : iCurView + 1);
- if (PtInRect(&m_rectIBText, point))
- DoViewSel();
- }
- }
-
- void CDIDeviceActionConfigPage::OnMouseOver(POINT point, WPARAM fwKeys)
- {
- CFlexWnd::s_ToolTip.SetEnable(FALSE);
-
- // Check view selection area so we can display text in info box.
- if (m_pDeviceUI->GetNumViews() > 1)
- {
- if (PtInRect(&m_rectIB, point))
- {
- SetInfoText(IDS_INFOMSG_VIEW_VIEWSEL);
- return;
- }
- }
-
- SetAppropriateDefaultText();
- }
-
- int GetActionIndexFromPointer(LPDIACTIONW p, LPDIACTIONFORMATW paf)
- {
- if (!p || !paf || !paf->rgoAction)
- return -1;
-
- int index = int((((LPBYTE)p) - ((LPBYTE)paf->rgoAction)) / (DWORD)sizeof(DIACTIONW));
-
- assert(&(paf->rgoAction[index]) == p);
-
- return index;
- }
-
- BOOL CDIDeviceActionConfigPage::IsActionAssignedHere(int index)
- {
- if (!m_lpDiac)
- return FALSE;
-
- if (index < 0 || index >= (int)m_lpDiac->dwNumActions)
- return FALSE;
-
- return IsEqualGUID(m_didi.guidInstance, m_lpDiac->rgoAction[index].guidInstance);
- }
-
- LRESULT CDIDeviceActionConfigPage::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- switch (msg)
- {
- case WM_UNHIGHLIGHT:
- // Unhighlight current callout
- ExitAssignState();
- break;
-
- case WM_KEYDOWN:
- #ifdef DBG
- // In debug version, shift-escape exits the UI.
- if (wParam == VK_ESCAPE && GetAsyncKeyState(VK_SHIFT) < 0)
- {
- PostMessage(GetParent(m_hWnd), WM_KEYDOWN, wParam, lParam);
- break;
- }
- #endif
- // If this is a keyboard device, then click-to-pick will take care of the functionalities below.
- // Process WM_KEYDOWN only for non-keyboard devices.
- if (LOBYTE(m_didi.dwDevType) == DI8DEVTYPE_KEYBOARD) return 0;
- switch(wParam)
- {
- case VK_RETURN:
- // If we are not in assign state, enter it.
- if (m_State == CFGSTATE_NORMAL && m_pCurControl)
- EnterAssignState();
- break;
-
- case VK_DELETE:
- // If we are in assign state and there is a control, unassign it.
- if (m_State == CFGSTATE_ASSIGN && m_pCurControl)
- UnassignCallout();
- break;
-
- case VK_ESCAPE:
- if (m_State == CFGSTATE_ASSIGN)
- ExitAssignState();
-
- break;
- }
- return 0;
-
- case WM_FLEXCHECKBOX:
- switch(wParam)
- {
- case CHKNOTIFY_UNCHECK:
- m_pDeviceUI->GetCurView()->SortAssigned(FALSE);
- if (m_pCurControl)
- {
- // Scroll so that we scroll to make this visible since it might be displaced by sorting.
- m_pDeviceUI->GetCurView()->ScrollToMakeControlVisible(m_pCurControl->GetCalloutMaxRect());
- }
- Invalidate();
- break;
- case CHKNOTIFY_CHECK:
- m_pDeviceUI->GetCurView()->SortAssigned(TRUE);
- if (m_pCurControl)
- {
- // Scroll so that we scroll to make this visible since it might be displaced by sorting.
- m_pDeviceUI->GetCurView()->ScrollToMakeControlVisible(m_pCurControl->GetCalloutMaxRect());
- }
- Invalidate();
- break;
- case CHKNOTIFY_MOUSEOVER:
- SetInfoText(m_CheckBox.GetCheck() ? IDS_INFOMSG_VIEW_SORTENABLED : IDS_INFOMSG_VIEW_SORTDISABLED);
- break;
- }
- break;
-
- case WM_FLEXCOMBOBOX:
- switch (wParam)
- {
- case FCBN_MOUSEOVER:
- if (lParam)
- {
- CFlexComboBox *pCombo = (CFlexComboBox*)lParam;
- if (pCombo->m_hWnd == m_UserNames.m_hWnd)
- SetInfoText(m_puig->InEditMode() ? IDS_INFOMSG_EDIT_USERNAME : IDS_INFOMSG_VIEW_USERNAME);
- else if (pCombo->m_hWnd == m_Genres.m_hWnd)
- SetInfoText(m_puig->InEditMode() ? IDS_INFOMSG_EDIT_GAMEMODE : IDS_INFOMSG_VIEW_GAMEMODE);
- }
- break;
-
- case FCBN_SELCHANGE:
- // Clear the tool tip as the combo-box has closed
- CFlexWnd::s_ToolTip.SetEnable(FALSE);
- CFlexWnd::s_ToolTip.SetToolTipParent(NULL);
- if (m_pUIFrame && m_puig)
- {
- ExitAssignState();
- m_pUIFrame->SetCurGenre(m_Genres.GetSel());
- int nUser = m_UserNames.GetSel();
- if (m_puig->GetNumUserNames() > 0 && nUser >= m_puig->GetNumUserNames())
- nUser = -1;
- m_pUIFrame->SetCurUser(m_nPageIndex, nUser);
- }
- break;
- }
- return 0;
-
- case WM_FLEXTREENOTIFY:
- {
- // Check if this is a mouse over message (just for info box update)
- if (wParam == FTN_MOUSEOVER)
- {
- SetAppropriateDefaultText();
- return FALSE;
- }
-
- if (!lParam)
- return FALSE;
- FLEXTREENOTIFY &n = *((FLEXTREENOTIFY *)(LPVOID)lParam);
- if (!n.pItem)
- return FALSE;
- switch (wParam)
- {
- case FTN_OWNERDRAW:
- {
- POINT ofs = {0, 0};
- CBitmap *pbmGlyph = NULL;
- BOOL bAssigned = FALSE, bAssignedHere = FALSE;
- if (n.pItem->IsUserGUID(GUID_ActionItem))
- {
- LPDIACTIONW lpac = GetItemLpac(n.pItem, 0);
- if (lpac)
- // We now walk through each DIACTION and find those with action name match, then see if
- // they are assigned anywhere.
- for (DWORD i = 0; i < m_lpDiac->dwNumActions; ++i)
- {
- if (wcscmp(lpac->lptszActionName, m_lpDiac->rgoAction[i].lptszActionName))
- continue;
-
- if (bAssignedHere = IsActionAssignedHere(i))
- {
- bAssigned = TRUE;
- break;
- }
- if (m_pUIFrame && m_pUIFrame->QueryActionAssignedAnywhere(m_didi.guidInstance, i) == S_OK)
- bAssigned = TRUE;
- }
- if (bAssigned || bAssignedHere)
- {
- pbmGlyph = bAssignedHere ? m_pbmCheckGlyph :
- m_pbmCheckGlyphDark;
- pbmGlyph->FigureSize();
- ofs.x = 2;
- ofs.y = 4;
- }
- }
- else
- {
- if (n.pItem == m_pRelAxesParent)
- pbmGlyph = m_pbmRelAxesGlyph;
- if (n.pItem == m_pAbsAxesParent)
- pbmGlyph = m_pbmAbsAxesGlyph;
- if (n.pItem == m_pButtonParent)
- pbmGlyph = m_pbmButtonGlyph;
- if (n.pItem == m_pHatParent)
- pbmGlyph = m_pbmHatGlyph;
- ofs.y = 2;
- }
- if (!pbmGlyph)
- return FALSE;
- n.pItem->PaintInto(n.hDC);
- RECT rect;
- CPaintHelper ph(*m_puig, n.hDC);
- ph.SetElement(UIE_GLYPH);
- n.pItem->GetMargin(rect);
- pbmGlyph->Draw(n.hDC, ofs.x, rect.top + ofs.y);
- return TRUE;
- }
-
- case FTN_CLICK:
- // We cannot assign a different control to this action if it has the DIA_APPFIXED flag.
- if (n.pItem->IsUserGUID(GUID_ActionItem) && GetItemLpac(n.pItem) && !(GetItemLpac(n.pItem)->dwFlags & DIA_APPFIXED))
- {
- m_Tree.SetCurSel(n.pItem);
- ActionClick(GetItemLpac(n.pItem));
- }
- else
- {
- #ifdef CFGUI__ALLOW_USER_ACTION_TREE_BRANCH_MANIPULATION
- if (!n.pItem->IsExpanded())
- n.pItem->Expand();
- else
- n.pItem->Collapse();
- #endif
- }
- break;
- }
- break;
- }
- }
-
- return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
- }
-
- void CDIDeviceActionConfigPage::SetInvalid(LPDIACTIONW lpac)
- {
- lpac->guidInstance = GUID_NULL;
- lpac->dwObjID = (DWORD)-1;
- }
-
- DWORD CDIDeviceActionConfigPage::GetOffset(LPDIACTIONW lpac)
- {
- return lpac ? lpac->dwObjID : (DWORD)-1;
- }
-
- void CDIDeviceActionConfigPage::SetOffset(LPDIACTIONW lpac, DWORD ofs)
- {
- assert(lpac != NULL);
- if (!lpac)
- return;
- lpac->dwObjID = ofs;
- }
-
- HRESULT CDIDeviceActionConfigPage::InitLookup()
- {
- DIDEVOBJSTRUCT os;
-
- HRESULT hresult = FillDIDeviceObjectStruct(os, m_lpDID);
-
- if (FAILED(hresult))
- return hresult;
-
- for (int i = 0; i < os.nObjects; i++)
- {
- DIDEVICEOBJECTINSTANCEW &doi = os.pdoi[i];
- offset_objid.add(doi.dwOfs, doi.dwType);
- }
-
- return S_OK;
- }
-
- HRESULT CDIDeviceActionConfigPage::SetEditLayout(BOOL bEditLayout)
- {
- m_pDeviceUI->SetEditMode(bEditLayout);
- return S_OK;
- }
-
-
- BOOL CDIDeviceActionConfigPage::IsControlMapped(CDeviceControl *pControl)
- {
- if (pControl == NULL)
- return FALSE;
-
- if (!pControl->IsOffsetAssigned())
- return FALSE;
-
- if (m_lpDiac == NULL)
- return FALSE;
-
- for (DWORD i = 0; i < m_lpDiac->dwNumActions; i++)
- if (GetOffset(&(m_lpDiac->rgoAction[i])) == pControl->GetOffset())
- return TRUE;
-
- return FALSE;
- }
-
- void CDIDeviceActionConfigPage::InitDevice()
- {
- if (m_lpDID == NULL || m_pDeviceUI == NULL || m_pUIFrame == NULL)
- return;
-
- HWND hWndMain = m_pUIFrame->GetMainHWND();
- if (!hWndMain)
- return;
-
- // don't do anything if this is a mouse
- switch ((DWORD)(LOBYTE(LOWORD(m_pDeviceUI->m_didi.dwDevType))))
- {
- case DI8DEVTYPE_MOUSE:
- return;
- }
-
- // init/prepare...
- int i;
- const DIDEVOBJSTRUCT &os = m_pDeviceUI->m_os;
- int nObjects = os.nObjects;
-
- DIDATAFORMAT df;
- df.dwSize = sizeof(DIDATAFORMAT);
- df.dwObjSize = sizeof(DIOBJECTDATAFORMAT);
- df.dwFlags = DIDF_ABSAXIS;
- df.dwDataSize = sizeof(DWORD) * (DWORD)nObjects;
- df.dwNumObjs = (DWORD)nObjects;
- df.rgodf = (DIOBJECTDATAFORMAT *)malloc(sizeof(DIOBJECTDATAFORMAT) * nObjects);
- if (df.rgodf == NULL)
- {
- etrace1(_T("Could not allocate DIOBJECTDATAFORMAT array of %d elements\n"), nObjects);
- return;
- }
-
- m_cbDeviceDataSize = df.dwDataSize;
- for (int c = 0; c < 2; c++)
- {
- if (m_pDeviceData[c] != NULL)
- free(m_pDeviceData[c]);
- m_pDeviceData[c] = (DWORD *)malloc(m_cbDeviceDataSize);
- if (m_pDeviceData[c] == NULL)
- etrace2(_T("Could not allocate device data buffer %d of %d bytes\n"), c, m_cbDeviceDataSize);
- }
- m_nOnDeviceData = 0;
- m_bFirstDeviceData = TRUE;
-
- for (i = 0; i < nObjects; i++)
- {
- DIOBJECTDATAFORMAT *podf = &(df.rgodf[i]);
- podf->pguid = NULL;
- podf->dwOfs = i * sizeof(DWORD);
- podf->dwType = os.pdoi[i].dwType;
- podf->dwFlags = 0;
- }
-
- if (df.rgodf != NULL)
- {
- HRESULT hr = m_lpDID->SetDataFormat(&df);
- free(df.rgodf);
- df.rgodf = NULL;
-
- if (FAILED(hr))
- {
- etrace1(_T("SetDataFormat() failed, returning 0x%08x\n"), hr);
- }
- else
- {
- hr = m_lpDID->SetCooperativeLevel(hWndMain, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
- if (FAILED(hr))
- etrace1(_T("SetCooperativeLevel() failed, returning 0x%08x\n"), hr);
-
- DIPROPRANGE range;
- range.diph.dwSize = sizeof(DIPROPRANGE);
- range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
- range.diph.dwObj = 0;
- range.diph.dwHow = DIPH_DEVICE;
- range.lMin = DEVICE_POLLING_AXIS_MIN;
- range.lMax = DEVICE_POLLING_AXIS_MAX;
-
- hr = m_lpDID->SetProperty(DIPROP_RANGE, (LPCDIPROPHEADER)&range);
- if (FAILED(hr))
- etrace1(_T("SetProperty(DIPROP_RANGE, ...) failed, returning 0x%08x\n"), hr);
-
- hr = m_lpDID->Acquire();
- if (FAILED(hr))
- etrace1(_T("Acquire() failed, returning 0x%08x\n"), hr);
- }
- }
- }
-
- void CALLBACK CDIDeviceActionConfigPage::DeviceTimerProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
- {
- if (!IsWindow((HWND)dwUser)) return; // Verify that dwUser is a valid window handle
- CDIDeviceActionConfigPage *pPage = (CDIDeviceActionConfigPage *)GetFlexWnd((HWND)dwUser); // Get flex object
- if (pPage)
- pPage->DeviceTimer();
- }
-
- void CDIDeviceActionConfigPage::DeviceTimer()
- {
- DWORD *pOldData = m_pDeviceData[m_nOnDeviceData];
- m_nOnDeviceData = (m_nOnDeviceData + 1) & 1;
- DWORD *pData = m_pDeviceData[m_nOnDeviceData];
-
- if (m_lpDID == NULL || pData == NULL || pOldData == NULL)
- {
- // Required data not available. Return and there'll be no more timer callbacks.
- etrace(_T("DeviceTimer() failed\n"));
- return;
- }
-
- // Get device data only if this page is visible.
- if (m_lpDiac)
- {
- HRESULT hr = m_lpDID->Poll();
- if (SUCCEEDED(hr))
- {
- hr = m_lpDID->GetDeviceState(m_cbDeviceDataSize, pData);
- if (SUCCEEDED(hr))
- {
- if (!m_bFirstDeviceData)
- {
- DeviceDelta(pData, pOldData);
- } else
- {
- m_bFirstDeviceData = FALSE;
- }
- } else
- {
- etrace1(_T("GetDeviceState() failed, returning 0x%08x\n"), hr);
- }
- } else
- {
- etrace1(_T("Poll() failed, returning 0x%08x\n"), hr);
- }
- }
-
- // Set the next timer event.
- if (g_fptimeSetEvent)
- g_fptimeSetEvent(DEVICE_POLLING_INTERVAL, DEVICE_POLLING_INTERVAL,
- CDIDeviceActionConfigPage::DeviceTimerProc, (DWORD_PTR)m_hWnd, TIME_ONESHOT);
- }
-
- void CDIDeviceActionConfigPage::DeviceDelta(DWORD *pData, DWORD *pOldData)
- {
- if (pData == NULL || pOldData == NULL || m_pDeviceUI == NULL)
- return;
-
- const DIDEVOBJSTRUCT &os = m_pDeviceUI->m_os;
-
- // see which objects changed
- for (int i = 0; i < os.nObjects; i++)
- {
- // for axes, we need to do special processing
- if (os.pdoi[i].dwType & DIDFT_AXIS)
- {
- BOOL bSig = FALSE, bOldSig = FALSE;
-
- StoreAxisDeltaAndCalcSignificance(os.pdoi[i],
- pData[i], pOldData[i], bSig, bOldSig);
-
- AxisDelta(os.pdoi[i], bSig, bOldSig);
-
- continue;
- }
-
- // for all others, skip that which didn't change
- if (pData[i] == pOldData[i])
- continue;
-
- // pass to appropriate delta function
- DWORD dwObjId = os.pdoi[i].dwType;
- if (dwObjId & DIDFT_BUTTON)
- ButtonDelta(os.pdoi[i], pData[i], pOldData[i]);
- else if (dwObjId & DIDFT_POV)
- PovDelta(os.pdoi[i], pData[i], pOldData[i]);
- }
- }
-
- void CDIDeviceActionConfigPage::StoreAxisDeltaAndCalcSignificance(const DIDEVICEOBJECTINSTANCEW &doi, DWORD data, DWORD olddata, BOOL &bSig, BOOL &bOldSig)
- {
- // see if this object has an axis value array
- int i;
- if (objid_avai.getright(doi.dwType, i))
- {
- AxisValueArray &ar = m_AxisValueArray[i];
- int on = ar[0] + 1;
- if (on >= ar.GetSize())
- on = DEVICE_POLLING_ACBUF_START_INDEX;
- ar[0] = on;
- int delta = abs(int(data) - int(olddata));
- // Scale up the delta if this is a wheel axis as wheels are harder to move generally.
- if (LOBYTE(m_didi.dwDevType) == DI8DEVTYPE_DRIVING && doi.guidType == GUID_XAxis)
- delta = delta * DEVICE_POLLING_WHEEL_SCALE_FACTOR;
- if (delta < DEVICE_POLLING_AXIS_MINDELTA)
- delta = 0;
- int cumul = ar[1]; // Retrieve cumulative value for easier processing
- cumul -= ar[on]; // Subtract value in current slot from cumul since it's being thrown away.
- cumul += delta; // Add current delta to cumul
- ar[on] = delta; // Store the delta at current slot
- ar[1] = cumul; // Save cumulative value
-
- bOldSig = (BOOL)ar[2];
- ar[2] = int(bSig = cumul > DEVICE_POLLING_AXIS_SIGNIFICANT);
- if (bSig)
- {
- // This axis is about to be activated. We now reset the history and cumulative movement since we don't need them any more.
- ar[0] = DEVICE_POLLING_ACBUF_START_INDEX;
- ar[1] = 0;
- ar[2] = FALSE;
- for (int c = DEVICE_POLLING_ACBUF_START_INDEX;
- c < DEVICE_POLLING_ACBUF_START_INDEX + DEVICE_POLLING_AXIS_ACCUMULATION; c++)
- ar[c] = 0;
- }
- }
- else
- {
- i = m_AxisValueArray.GetSize();
- m_AxisValueArray.SetSize(i + 1);
- objid_avai.add(doi.dwType, i);
- AxisValueArray &ar = m_AxisValueArray[i];
- ar.SetSize(DEVICE_POLLING_ACBUF_START_INDEX + DEVICE_POLLING_AXIS_ACCUMULATION);
- ar[0] = DEVICE_POLLING_ACBUF_START_INDEX;
- ar[1] = 0;
- ar[2] = FALSE;
- for (int c = DEVICE_POLLING_ACBUF_START_INDEX;
- c < DEVICE_POLLING_ACBUF_START_INDEX + DEVICE_POLLING_AXIS_ACCUMULATION; c++)
- ar[c] = 0;
-
- bOldSig = bSig = FALSE;
- }
- }
-
- void CDIDeviceActionConfigPage::AxisDelta(const DIDEVICEOBJECTINSTANCEW &doi, BOOL data, BOOL old)
- {
- if (data && !old)
- {
- if (m_State == CFGSTATE_NORMAL)
- ActivateObject(doi);
- }
- if (old && !data)
- DeactivateObject(doi);
- }
-
- void CDIDeviceActionConfigPage::ButtonDelta(const DIDEVICEOBJECTINSTANCEW &doi, DWORD data, DWORD old)
- {
- static DWORD dwLastOfs;
- static DWORD dwLastTimeStamp;
-
- if (data && !old)
- {
- // Do special processing for keyboard
- if (LOBYTE(m_didi.dwDevType) == DI8DEVTYPE_KEYBOARD)
- {
- // If this is an ENTER key, we enter the assign state if not already in it.
- if (doi.dwOfs == DIK_RETURN || doi.dwOfs == DIK_NUMPADENTER)
- {
- if (m_State == CFGSTATE_NORMAL && m_pCurControl)
- EnterAssignState();
- return; // Do nothing other than entering the assign state. No highlighting
- }
-
- // DELETE key case
- // If we are in assign state and there is a control, unassign it.
- if (doi.dwOfs == DIK_DELETE && m_State == CFGSTATE_ASSIGN && m_pCurControl)
- {
- UnassignCallout();
- return; // Don't highlight or do pick to click for delete if this press happens during assign state.
- }
-
- // ESCAPE key case
- if (doi.dwOfs == DIK_ESCAPE && m_State == CFGSTATE_ASSIGN)
- {
- ExitAssignState();
- return;
- }
-
- // For all other keys, still process click-to-pick or highlighting.
- }
-
- // Enter assign state if this is a double activation
- if (m_State == CFGSTATE_NORMAL)
- {
- ActivateObject(doi);
-
- if (doi.dwOfs == dwLastOfs && dwLastTimeStamp + GetDoubleClickTime() > GetTickCount())
- {
- // We check if a callout for this control exists. If not, do not enter assign state.
- CDeviceView *pCurView = m_pDeviceUI->GetCurView();
- CDeviceControl *pControl = pCurView->GetControlFromOfs(doi.dwType);
- if (pControl)
- EnterAssignState();
- }
- dwLastOfs = doi.dwOfs;
- dwLastTimeStamp = GetTickCount();
- }
- }
- if (old && !data)
- DeactivateObject(doi);
- }
-
- void CDIDeviceActionConfigPage::PovDelta(const DIDEVICEOBJECTINSTANCEW &doi, DWORD data, DWORD old)
- {
- BOOL d = data != -1, o = old != -1;
-
- if (d && !o)
- {
- if (m_State == CFGSTATE_NORMAL)
- ActivateObject(doi);
- }
- if (o && !d)
- DeactivateObject(doi);
- }
-
- void CDIDeviceActionConfigPage::ActivateObject(const DIDEVICEOBJECTINSTANCEW &doi)
- {
- if (m_pDeviceUI == NULL)
- return;
-
-
- CDeviceView *pCurView = m_pDeviceUI->GetCurView(), *pView = pCurView;
- if (pView == NULL)
- return;
-
- CDeviceControl *pControl = pView->GetControlFromOfs(doi.dwType);
- if (pControl == NULL)
- {
- for (int i = 0; i < m_pDeviceUI->GetNumViews(); i++)
- {
- pView = m_pDeviceUI->GetView(i);
- if (pView == NULL)
- continue;
-
- pControl = pView->GetControlFromOfs(doi.dwType);
- if (pControl != NULL)
- break;
- }
-
- if (pControl != NULL && pView != NULL && pView != pCurView)
- {
- // switch to view
- m_pDeviceUI->SetView(pView);
- SetControlAssignments();
- SetCurrentControl(NULL);
- }
- }
-
- if (pControl != NULL)
- SetCurrentControl(pControl);
-
- SetAppropriateDefaultText();
- }
-
- void CDIDeviceActionConfigPage::DeactivateObject(const DIDEVICEOBJECTINSTANCEW &doi)
- {
- // Add code that needs to be run when deactivating here.
- }
-
- HRESULT CDIDeviceActionConfigPage::Unacquire()
- {
- if (m_lpDID != NULL)
- m_lpDID->Unacquire();
-
- return S_OK;
- }
-
- HRESULT CDIDeviceActionConfigPage::Reacquire()
- {
- InitDevice();
-
- return S_OK;
- }
-
- void CDIDeviceActionConfigPage::EnterAssignState()
- {
- if (!m_puig->InEditMode())
- return;
- if (!m_pCurControl || m_pCurControl->IsFixed())
- return;
- SetInfoText(IDS_INFOMSG_EDIT_EDITMODEENABLED);
- m_State = CFGSTATE_ASSIGN; // Into the assign state.
- ShowCurrentControlAssignment(); // Show the tree
- m_Tree.Invalidate();
- Invalidate();
- }
-
- void CDIDeviceActionConfigPage::ExitAssignState()
- {
- m_State = CFGSTATE_NORMAL; // Out of the assign state.
- SetCurrentControl(NULL); // Unselect the control
- ShowCurrentControlAssignment(); // Show the tree
- m_Tree.Invalidate();
- Invalidate();
- SetAppropriateDefaultText();
- }
-
- HRESULT CDIDeviceActionConfigPage::SetInfoText(int iCode)
- {
- // We check for special code -1 here. This is only called by CConfigWnd, and means that we should
- // call SetAppropriateDefaultText to display proper text.
- if (iCode == -1)
- SetAppropriateDefaultText();
- else
- m_InfoBox.SetText(iCode);
- return S_OK;
- }
-
- void CDIDeviceActionConfigPage::SetAppropriateDefaultText()
- {
- if (m_puig->InEditMode())
- {
- if (m_State == CFGSTATE_ASSIGN)
- SetInfoText(IDS_INFOMSG_EDIT_EDITMODEENABLED);
- else if (m_pCurControl)
- {
- if (m_pCurControl->IsFixed())
- SetInfoText(IDS_INFOMSG_APPFIXEDSELECT);
- else
- SetInfoText(IDS_INFOMSG_EDIT_CTRLSELECTED);
- }
- else
- {
- if (LOBYTE(m_didi.dwDevType) == DI8DEVTYPE_KEYBOARD)
- SetInfoText(IDS_INFOMSG_EDIT_KEYBOARD);
- else
- if (LOBYTE(m_didi.dwDevType) == DI8DEVTYPE_MOUSE)
- SetInfoText(IDS_INFOMSG_EDIT_MOUSE);
- else
- SetInfoText(IDS_INFOMSG_EDIT_DEVICE);
- }
- } else
- SetInfoText(IDS_INFOMSG_VIEW_DEVICE);
- }
-